home *** CD-ROM | disk | FTP | other *** search
- #include <graphics libraries.h>
- #include <graphics toolbox.h>
- #include <offscreen library.h>
- #include "SymmetryUtils.h"
- #include "TileConstants.h"
- #include "TileProtos.h"
- #include "Group1.h"
-
- extern gxPatternRecord gPattern; // The pattern that we fill the window with
- extern gxShape gTileShape; // The shape that the pattern repeats
- extern dragger gDragger; // A record containing a manipulable contour & associated stuff
- extern gxShape gOpShapes[]; // Group of shapes to show the
- // symmetry operations
- extern gxViewPort gViewPort;
- extern Boolean gContRedraw, gKeepClosed;
-
- ///////////////////////////////////////////////////////////////////////////////////
- // Group p1
-
- // Test for a hit on an op shape, tracking the drag and returning true
- // if one was hit, false otherwise
- Boolean p1_OpShapeHit(gxPoint *clickPt)
- {
- gxHitTestInfo hitStats;
- gxShape hitShape, oldShape;
- gxTransform xForm;
- long shapeNum;
-
- // Test the two translators for a hit
- for(shapeNum = 0; shapeNum < 2; shapeNum++)
- {
- hitShape = gOpShapes[shapeNum];
- xForm = GXGetShapeTransform(hitShape);
-
- // Test only for a hit on the end cap
- GXIgnoreGraphicsNotice(attributes_already_set);
- GXSetTransformHitTest(xForm, gxEndCapPart, kHitTolerance);
- GXPopGraphicsNotice();
-
- // If shape was hit, we're done looking
- if(GXHitTestShape(hitShape, clickPt, &hitStats))
- break;
- }
-
- // If a shape was hit, track it
- if(shapeNum < 2)
- {
- gxLine theLine;
- gxPoint anchor, pt, lastPt = *clickPt;;
-
- hitShape = gOpShapes[shapeNum];
-
- // Get the "anchor" point (the tail of the arrow)
- GXGetLine(hitShape, &theLine);
- anchor = theLine.first;
-
- // Create a shape for saving the old position
- if(!gContRedraw)
- oldShape = GXCopyToShape(nil, hitShape);
-
- // Follow the drag around
- while(StillDown())
- {
- // Get the new mouse position and if it's different,
- // adjust the dragged shape
- GXGetViewPortMouse(gViewPort, &pt);
- if(pt.x != lastPt.x || pt.y != lastPt.y)
- {
- // Save old shape so we can erase and draw in rapid succession
- if(!gContRedraw)
- {
- GXCopyToShape(oldShape, hitShape);
-
- // If constraints are on, erase the dragger before.
- if(gKeepClosed)
- EraseAShape(gDragger.snake1);
- }
-
- // Move it
- p1_DragOpShape(hitShape, &pt, &anchor);
-
- if(gContRedraw)
- {
- // Reset pattern and draw it right now
- p1_ChangeLattice();
- OffToScreen();
- }
- else
- {
- // Erase and draw
- EraseAShape(oldShape);
- GXDrawShape(hitShape);
-
- // If constraints are on, draw the dragger too.
- if(gKeepClosed)
- GXDrawShape(gDragger.snake1);
- }
- }
- lastPt = pt;
- }
- if(!gContRedraw)
- {
- p1_ChangeLattice(); // Update the pattern
- GXDisposeShape(oldShape);
- }
- return true;
- }
- else // no shape hit
- return false;
- }
-
- // Moves the op shape and dragger as appropriate
- void p1_DragOpShape(gxShape dragShape, gxPoint *clickPt, gxPoint *anchor)
- {
- fixed xd = clickPt->x - anchor->x, yd = clickPt->y - anchor->y,
- lxd = labs(clickPt->x - anchor->x), lyd = labs(clickPt->y - anchor->y);
- gxPoint temp;
- gxLine theLine;
-
- // Get the current line
- GXGetLine(dragShape, &theLine);
-
- // If the point is in bounds, just use it
- if(lxd < kMaxDistance && lyd < kMaxDistance &&
- (lyd > kMinDistance || lxd > kMinDistance) )
- {
- theLine.last = *clickPt;
- }
- else // Constrain it to the bounds
- {
- temp = *clickPt;
- if( lxd > kMaxDistance )
- temp.x = anchor->x + ( (xd < 0) ? -kMaxDistance : kMaxDistance);
- else if( lxd < kMinDistance )
- temp.x = anchor->x + ( (xd < 0) ? -kMinDistance : kMinDistance);
-
- if( lyd > kMaxDistance )
- temp.y = anchor->y + ( (yd < 0) ? -kMaxDistance : kMaxDistance);
- else if( lyd < kMinDistance )
- temp.y = anchor->y + ( (yd < 0) ? -kMinDistance : kMinDistance);
-
- theLine.last = temp;
- }
-
- // Set the new geometry
- GXSetLine(dragShape, &theLine);
-
- // If constraints are on, adjust the dragger too
- if(gKeepClosed)
- {
- long slaveIndex;
-
- slaveIndex = (dragShape == gOpShapes[0]) ? gDragger.slavePt[0] : gDragger.slavePt[2];
- GXSetShapePoints(gDragger.snake1, slaveIndex, 1, &theLine.last);
- }
- }
-
- // Called either to set the default shapes when resetting the tile, or when
- // the symmetry has changed, to convert one lattice type to another.
- // Currently only resets to default
- void p1_RemakeOpShapes(Boolean useDefaults)
- {
- gxShape tempShape;
- gxLine aLine;
-
- if(true /* useDefaults */)
- {
- tempShape = MakeOpShape(transOp);
- GXMoveShape(tempShape, kStartingOffset, kStartingOffset);
- gOpShapes[0] = GXCopyToShape(nil, tempShape);
- gOpShapes[1] = tempShape;
- GXGetLine(gOpShapes[1], &aLine);
- aLine.last.x = aLine.first.x + kStartingGridSize;
- aLine.last.y = aLine.first.y;
- GXSetLine(gOpShapes[1], &aLine);
- }
- else
- {
- // Look at gPattern to determine the lattice, build new op shapes accordingly
- }
- }
-
- // Set the dragger to the default shape
- void p1_SetDefaultDragger(gxShape snake)
- {
- long dragPoly[] = { 1, // number of contours
- 3, // number of points
- ff(0), ff(64),
- ff(0), ff(0),
- ff(64), ff(0) };
-
-
- // make the starting drag shape
- GXSetPolygons(snake, (gxPolygons *) dragPoly);
- GXMoveShape(snake, kStartingOffset, kStartingOffset);
-
- // Reset the pattern to match the op shapes
- p1_ChangeLattice();
- }
-
- // Reset the pattern vectors according to the positions of the op shapes
- void p1_ChangeLattice(void)
- {
- gxLine line1, line2;
-
- // Adjust points to define the true unit cell.
- // We just get the vectors direct from the shapes
- GXGetLine(gOpShapes[0], &line2);
- gPattern.v.x = line2.last.x - line2.first.x;
- gPattern.v.y = line2.last.y - line2.first.y;
- GXGetLine(gOpShapes[1], &line1);
- gPattern.u.x = line1.last.x - line1.first.x;
- gPattern.u.y = line1.last.y - line1.first.y;
-
- // Now remake the pattern according to the new lattice and draw it offscreen
- RemakeTile();
- }
-
- // Repeat the dragger geometry as necessary to build up the full unit cell
- //void p1_BuildCellShape(gxShape snake)
- //{
- //} *** Not needed, since the geometry isn't repeated in p1 ***
-
-
- // Force the dragger to describe a closed tile
- void p1_AttachConstraints(void)
- {
- long numPts;
- gxLine line1, line2;
-
- // Get the 2 lines
- GXGetLine(gOpShapes[0], &line1);
- GXGetLine(gOpShapes[1], &line2);
-
- // Get the number of points in the snake
- numPts = GXCountShapePoints(gDragger.snake1, 1);
- if(numPts < 3)
- {
- // There can't be only one point, so there must be 2.
- // so we just need to add 1 point to the end of the snake
-
- gxPoint newPt[] = {1L, 1L, 0, 0}; // A polygons structure with 1 point
-
- // Get the point into our poly structure
- GXGetShapePoints(gDragger.snake1, numPts, 1, &newPt[1]);
-
- // add it to the snake
- GXSetPolygonParts(gDragger.snake1, 0, 0, (gxPolygons *)newPt,
- gxBreakNeitherEdit);
- numPts = 3;
- }
-
- // Store the three indices in this order: V, O, U
- gDragger.slavePt[0] = 1;
- gDragger.slavePt[1] = (numPts < 4) ? 2 : (numPts / 2);
- gDragger.slavePt[2] = numPts;
-
- // Reset the dragger geometry
- GXSetShapePoints(gDragger.snake1, gDragger.slavePt[0], 1, &line1.last);
- GXSetShapePoints(gDragger.snake1, gDragger.slavePt[1], 1, &line1.first);
- GXSetShapePoints(gDragger.snake1, gDragger.slavePt[2], 1, &line2.last);
-
- // Now remake the pattern according to the new dragger and redraw it
- RemakeTile();
- }
-
- Boolean p1_IsVectorPoint(long ptIndex)
- {
- return( ptIndex == gDragger.slavePt[0] ||
- ptIndex == gDragger.slavePt[1] ||
- ptIndex == gDragger.slavePt[2] );
- }
-
- void p1_AddedDragPoint(long prevIndex)
- {
- // adjust our indexes
- if(prevIndex < gDragger.slavePt[2])
- gDragger.slavePt[2]++;
- if(prevIndex < gDragger.slavePt[1])
- gDragger.slavePt[1]++;
- }
-
- void p1_RemovedDragPoint(long index)
- {
- // adjust our indexes
- gDragger.slavePt[2]--; // always decrement last point
- if(index < gDragger.slavePt[1])
- gDragger.slavePt[1]--;
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////////
- // Group pg
-
- // Test for a hit on an op shape, tracking the drag and returning true
- // if one was hit, false otherwise
- Boolean pg_OpShapeHit(gxPoint *clickPt)
- {
- gxHitTestInfo hitStats;
- gxShape hitShape, oldShape1, oldShape2;
- gxTransform xForm;
- long shapeNum;
- Boolean arrowHit = false;
-
- // Test the two glide lines for a hit, arrow head first
- for(shapeNum = 0; shapeNum < 2; shapeNum++)
- {
- hitShape = gOpShapes[shapeNum];
- xForm = GXGetShapeTransform(hitShape);
-
- // Test for a hit on the end cap
- GXIgnoreGraphicsNotice(attributes_already_set);
- GXSetTransformHitTest(xForm, gxEndCapPart, kHitTolerance);
- GXPopGraphicsNotice();
-
- // If shape was hit, we're done looking
- if(GXHitTestShape(hitShape, clickPt, &hitStats))
- break;
- }
-
- // if a hit, it was an arrow
- if(shapeNum < 2)
- {
- arrowHit = true;
- }
- else // Try for a regular line hit
- {
- for(shapeNum = 0; shapeNum < 2; shapeNum++)
- {
- hitShape = gOpShapes[shapeNum];
- xForm = GXGetShapeTransform(hitShape);
-
- // Test for a hit on the geometry
- GXIgnoreGraphicsNotice(attributes_already_set);
- GXSetTransformHitTest(xForm, gxGeometryPart, kHitTolerance);
- GXPopGraphicsNotice();
-
- // If shape was hit, we're done looking
- if(GXHitTestShape(hitShape, clickPt, &hitStats))
- break;
- }
- }
-
- // If a shape was hit, track it
- if(shapeNum < 2)
- {
- gxShape otherShape;
- gxLine theLine, otherLine;
- gxPoint anchor, pt, lastPt = *clickPt;
-
- // set up the local references to the shapes
- if(shapeNum == 0)
- {
- hitShape = gOpShapes[0];
- otherShape = gOpShapes[1];
- }
- else
- {
- hitShape = gOpShapes[1];
- otherShape = gOpShapes[0];
- }
- // Get the "anchor" point (the first point of the other line)
- GXGetLine(otherShape, &otherLine);
- anchor = otherLine.first;
-
- // Create shapes for saving the old positions
- if(!gContRedraw)
- {
- oldShape1 = GXCopyToShape(nil, hitShape);
- oldShape2 = GXCopyToShape(nil, otherShape);
- }
-
- // Follow the drag around while the mouse is down
- while(StillDown())
- {
- // Get the new mouse position and if it's different,
- // adjust the dragged shape
- GXGetViewPortMouse(gViewPort, &pt);
- if(pt.x != lastPt.x || pt.y != lastPt.y)
- {
- // Save old shapes so we can erase and draw in rapid succession
- if(!gContRedraw)
- {
- GXCopyToShape(oldShape1, hitShape);
- GXCopyToShape(oldShape2, otherShape);
-
- // If constraints are on, erase the dragger before.
- if(gKeepClosed)
- EraseAShape(gDragger.snake1);
- }
-
- // Move it
- pg_DragOpShape(hitShape, otherShape, &pt, &lastPt, &anchor, arrowHit);
-
- if(gContRedraw)
- {
- // Reset pattern and draw it right now
- pg_ChangeLattice();
- OffToScreen();
- }
- else
- {
- // Erase and draw
- EraseAShape(oldShape1);
- GXDrawShape(hitShape);
-
- EraseAShape(oldShape2);
- GXDrawShape(otherShape);
-
- // If constraints are on, draw the dragger too.
- if(gKeepClosed)
- GXDrawShape(gDragger.snake1);
- }
- }
- lastPt = pt;
- }
- if(!gContRedraw)
- {
- pg_ChangeLattice(); // Update the pattern
- GXDisposeShape(oldShape1);
- GXDisposeShape(oldShape2);
- }
- return true;
- }
- else // no shape hit
- return false;
- }
-
- // Moves the op shape and dragger as appropriate
- void pg_DragOpShape(gxShape dragShape, gxShape otherShape, gxPoint *newPt, gxPoint *lastPt, gxPoint *anchor,
- Boolean arrowHit)
- {
- gxLine theLine, otherLine;
-
- // First drag the glide shape
- DragGlideShape(dragShape, newPt, lastPt, anchor, constrainH, arrowHit);
- GXGetLine(dragShape, &theLine);
-
- // Make the other one the same length if length changed
- if(arrowHit)
- {
- GXGetLine(otherShape, &otherLine);
- otherLine.last.y = theLine.last.y;
- GXSetLine(otherShape, &otherLine);
- }
-
- // If constraints are on, adjust the dragger too
- if(gKeepClosed)
- {
- GXGetLine(otherShape, &otherLine);
-
- if(dragShape == gOpShapes[0])
- {
- GXSetShapePoints(gDragger.snake1, gDragger.slavePt[0], 1, &theLine.last);
- GXSetShapePoints(gDragger.snake1, gDragger.slavePt[1], 1, &theLine.first);
-
- otherLine.first.x += (otherLine.first.x - theLine.first.x);
- GXSetShapePoints(gDragger.snake1, gDragger.slavePt[2], 1, &otherLine.first);
- }
- else // hit second line, only set 0 and 2
- {
- GXSetShapePoints(gDragger.snake1, gDragger.slavePt[0], 1, &otherLine.last);
-
- theLine.first.x += (theLine.first.x - otherLine.first.x);
- GXSetShapePoints(gDragger.snake1, gDragger.slavePt[2], 1, &theLine.first);
- }
- }
- }
-
-
-
- // Called either to set the default shapes when resetting the tile, or when
- // the symmetry has changed, to convert one lattice type to another.
- // Currently only resets to default
- void pg_RemakeOpShapes(Boolean useDefaults)
- {
- gxShape tempShape;
- gxLine aLine;
-
- if(true /* useDefaults */)
- {
- tempShape = MakeOpShape(glideOp);
- GXMoveShape(tempShape, kStartingOffset, kStartingOffset);
- gOpShapes[0] = GXCopyToShape(nil, tempShape);
- gOpShapes[1] = tempShape;
- GXMoveShape(gOpShapes[1], kStartingGridSize / 2, 0);
- }
- }
-
- // Set the dragger to the default shape.
- void pg_SetDefaultDragger(gxShape snake)
- {
- long dragPoly[] = { 1, // number of contours
- 3, // number of points
- ff(0), ff(64),
- ff(0), ff(0),
- ff(64), ff(0) };
-
-
- // make the starting drag shape
- GXSetPolygons(snake, (gxPolygons *) dragPoly);
- GXMoveShape(snake, kStartingOffset, kStartingOffset);
-
- // Reset the pattern to match the op shapes
- pg_ChangeLattice();
- }
-
- // Reset the pattern vectors according to the positions of the op shapes
- void pg_ChangeLattice(void)
- {
- gxLine line1, line2;
-
- // Adjust points to define the true unit cell.
- GXGetLine(gOpShapes[0], &line1);
- GXGetLine(gOpShapes[1], &line2);
- gPattern.u.x = 2 * (line2.first.x - line1.first.x);
- gPattern.u.y = 0;
- gPattern.v.x = 0;
- gPattern.v.y = 2 * (line1.last.y - line1.first.y);
-
- // Now remake the pattern according to the new lattice and draw it offscreen
- RemakeTile();
- }
-
- // Repeat the dragger geometry as necessary to build up the full unit cell.
- // Assumes the pattern vectors are set to correctly define the lattice
- void pg_BuildCellShape(gxShape snake)
- {
- gxShape tempShape;
- fixed dist;
- gxLine aLine;
- gxPoint ctr;
-
- // Get the point to reflect around
- GXGetLine(gOpShapes[0], &aLine);
- ctr.x = aLine.first.x;
- ctr.y = 0;
- // GXGetLine(gOpShapes[1], &aLine);
- // if(aLine.first.x < ctr.x)
- // ctr.x = aLine.first.x;
- ctr.x += gPattern.u.x / 2;
-
- // Get the glide distance
- dist = gPattern.v.y / 2;
-
- // Copy the shape, glide reflect it, and add it back in
- tempShape = GXCopyToShape(nil, gTileShape);
- GXMoveShape(tempShape, 0, dist);
- GXScaleShape(tempShape, -ff(1), ff(1), ctr.x, ctr.y);
- GXSetShapeParts(gTileShape, 0, gxSelectToEnd, tempShape, gxBreakLeftEdit);
- GXDisposeShape(tempShape);
- }
-
- // Force the dragger to describe a closed tile. Much like the p1 version.
- void pg_AttachConstraints(void)
- {
- long numPts;
- gxLine line1, line2;
-
- // Get the 2 lines
- GXGetLine(gOpShapes[0], &line1);
- GXGetLine(gOpShapes[1], &line2);
-
- // Get the number of points in the snake
- numPts = GXCountShapePoints(gDragger.snake1, 1);
- if(numPts < 3)
- {
- // There can't be only one point, so there must be 2.
- // so we just need to add 1 point to the end of the snake
-
- gxPoint newPt[] = {1L, 1L, 0, 0}; // A polygons structure with 1 point
-
- // Get the point into our poly structure
- GXGetShapePoints(gDragger.snake1, numPts, 1, &newPt[1]);
-
- // add it to the snake
- GXSetPolygonParts(gDragger.snake1, 0, 0, (gxPolygons *)newPt,
- gxBreakNeitherEdit);
- numPts = 3;
- }
-
- // Store the three indices in this order: V, O, U
- gDragger.slavePt[0] = 1;
- gDragger.slavePt[1] = (numPts < 4) ? 2 : (numPts / 2);
- gDragger.slavePt[2] = numPts;
-
- // Reset the dragger geometry
- GXSetShapePoints(gDragger.snake1, gDragger.slavePt[0], 1, &line1.last);
- GXSetShapePoints(gDragger.snake1, gDragger.slavePt[1], 1, &line1.first);
- line2.first.x += (line2.first.x - line1.first.x);
- GXSetShapePoints(gDragger.snake1, gDragger.slavePt[2], 1, &line2.first); // This is the only difference with p1
-
- // Now remake the pattern according to the new dragger and redraw it
- RemakeTile();
- }
-
- Boolean pg_IsVectorPoint(long ptIndex)
- {
- p1_IsVectorPoint(ptIndex);
- }
-
- void pg_AddedDragPoint(long prevIndex)
- {
- p1_AddedDragPoint(prevIndex);
- }
-
- void pg_RemovedDragPoint(long index)
- {
- p1_RemovedDragPoint(index);
- }
-
-
- ///////////////////////////////////////////////////////////////////////////////////
- // Group pm
-
- // Test for a hit on an op shape, tracking the drag and returning true
- // if one was hit, false otherwise
- Boolean pm_OpShapeHit(gxPoint *clickPt)
- {
- gxHitTestInfo hitStats;
- gxShape hitShape, oldShape;
- gxTransform xForm;
- long shapeNum;
-
- // Test the two mirror lines for a hit, arrow head first
- for(shapeNum = 0; shapeNum < 2; shapeNum++)
- {
- hitShape = gOpShapes[shapeNum];
- xForm = GXGetShapeTransform(hitShape);
-
- // Test for a hit on the geometry
- GXIgnoreGraphicsNotice(attributes_already_set);
- GXSetTransformHitTest(xForm, gxGeometryPart, kHitTolerance);
- GXPopGraphicsNotice();
-
- // If shape was hit, we're done looking
- if(GXHitTestShape(hitShape, clickPt, &hitStats))
- break;
- }
-
- // If a shape was hit, track it
- if(shapeNum < 2)
- {
- gxShape otherShape;
- gxLine theLine, otherLine;
- gxPoint anchor, pt, lastPt = *clickPt;
-
- // set up the local references to the shapes
- if(shapeNum == 0)
- {
- hitShape = gOpShapes[0];
- otherShape = gOpShapes[1];
- }
- else
- {
- hitShape = gOpShapes[1];
- otherShape = gOpShapes[0];
- }
- // Get the "anchor" point (the first point of the other line)
- GXGetLine(otherShape, &otherLine);
- anchor = otherLine.first;
-
- // Create a shape for saving the old position
- if(!gContRedraw)
- oldShape = GXCopyToShape(nil, hitShape);
-
- // Follow the drag around while the mouse is down
- while(StillDown())
- {
- // Get the new mouse position and if it's different,
- // adjust the dragged shape
- GXGetViewPortMouse(gViewPort, &pt);
- if(pt.x != lastPt.x || pt.y != lastPt.y)
- {
- // Save old shape so we can erase and draw in rapid succession
- if(!gContRedraw)
- GXCopyToShape(oldShape, hitShape);
-
- // Move it
- DragLineShape(hitShape, &pt, &lastPt, &anchor, constrainH);
-
- if(gContRedraw)
- {
- // Reset pattern and draw it right now
- pm_ChangeLattice();
- OffToScreen();
- }
- else
- {
- // Erase and draw
- EraseAShape(oldShape);
- GXDrawShape(hitShape);
- }
- }
- lastPt = pt;
- }
- if(!gContRedraw)
- {
- pm_ChangeLattice(); // Update the pattern
- GXDisposeShape(oldShape);
- }
- return true;
- }
- else // no shape hit
- return false;
- }
-
- // Called either to set the default shapes when resetting the tile, or when
- // the symmetry has changed, to convert one lattice type to another.
- // Currently only resets to default
- void pm_RemakeOpShapes(Boolean useDefaults)
- {
- gxShape tempShape;
- gxLine aLine;
-
- if(true /* useDefaults */)
- {
- tempShape = MakeOpShape(reflOp);
- GXMoveShape(tempShape, kStartingOffset, kStartingOffset);
- gOpShapes[0] = GXCopyToShape(nil, tempShape);
- gOpShapes[1] = tempShape;
- GXMoveShape(gOpShapes[1], kStartingGridSize, 0);
- }
- }
-
- // Set the dragger to the default shape.
- void pm_SetDefaultDragger(gxShape snake)
- {
- long dragPoly[] = { 1, // number of contours
- 2, // number of points
- ff(0), ff(0),
- ff(64), ff(0) };
-
-
- // make the starting drag shape
- GXSetPolygons(snake, (gxPolygons *) dragPoly);
- GXMoveShape(snake, kStartingOffset, kStartingOffset);
-
- // Reset the pattern to match the op shapes
- pm_ChangeLattice();
- }
-
- // Reset the pattern vectors according to the positions of the op shapes
- void pm_ChangeLattice(void)
- {
- gxLine line1, line2;
-
- // Adjust points to define the true unit cell.
- GXGetLine(gOpShapes[0], &line1);
- GXGetLine(gOpShapes[1], &line2);
- gPattern.u.x = 2 * (line2.first.x - line1.first.x);
- gPattern.u.y = 0;
- gPattern.v.x = 0;
- gPattern.v.y = kStartingGridSize;
-
- // Now remake the pattern according to the new lattice and draw it offscreen
- RemakeTile();
- }
-
- // Repeat the dragger geometry as necessary to build up the full unit cell
- void pm_BuildCellShape(gxShape snake)
- {
- gxShape tempShape;
- gxLine aLine;
- gxPoint ctr;
-
- // Get the point to reflect around
- GXGetLine(gOpShapes[0], &aLine);
- ctr.x = aLine.first.x;
- ctr.y = 0;
- ctr.x += gPattern.u.x / 2;
-
- // Copy the shape, reflect it, and add it back in
- tempShape = GXCopyToShape(nil, gTileShape);
- GXScaleShape(tempShape, -ff(1), ff(1), ctr.x, ctr.y);
- GXSetShapeParts(gTileShape, 0, gxSelectToEnd, tempShape, gxBreakLeftEdit);
- GXDisposeShape(tempShape);
- }
-
- ///////////////////////////////////////////////////////////////////////////////////
- // Group cm
-
- // Test for a hit on an op shape, tracking the drag and returning true
- // if one was hit, false otherwise
- Boolean cm_OpShapeHit(gxPoint *clickPt)
- {
- gxHitTestInfo hitStats;
- gxShape hitShape, oldShape;
- gxTransform xForm;
- long shapeNum;
- Boolean arrowHit;
-
- // Test the glide line arrow head for a hit first
- shapeNum = 1;
- hitShape = gOpShapes[shapeNum];
- xForm = GXGetShapeTransform(hitShape);
-
- // Test for a hit on the end cap
- GXIgnoreGraphicsNotice(attributes_already_set);
- GXSetTransformHitTest(xForm, gxEndCapPart, kHitTolerance);
- GXPopGraphicsNotice();
-
- // If shape was hit, log the fact
- if(GXHitTestShape(hitShape, clickPt, &hitStats))
- arrowHit = true;
- else // Try for a regular line hit
- {
- for(shapeNum = 0; shapeNum < 2; shapeNum++)
- {
- hitShape = gOpShapes[shapeNum];
- xForm = GXGetShapeTransform(hitShape);
-
- // Test for a hit on the geometry
- GXIgnoreGraphicsNotice(attributes_already_set);
- GXSetTransformHitTest(xForm, gxGeometryPart, kHitTolerance);
- GXPopGraphicsNotice();
-
- // If shape was hit, we're done looking
- if(GXHitTestShape(hitShape, clickPt, &hitStats))
- break;
- }
- }
-
- // If a shape was hit, track it
- if(shapeNum < 2)
- {
- gxShape otherShape;
- gxLine theLine, otherLine;
- gxPoint anchor, pt, lastPt = *clickPt;
-
- // set up the local references to the shapes
- if(shapeNum == 0)
- {
- hitShape = gOpShapes[0];
- otherShape = gOpShapes[1];
- }
- else
- {
- hitShape = gOpShapes[1];
- otherShape = gOpShapes[0];
- }
- // Get the "anchor" point (the x coord of the other line, and the y coord of this one)
- GXGetLine(hitShape, &theLine);
- GXGetLine(otherShape, &otherLine);
- anchor.x = otherLine.first.x;
- anchor.y = theLine.first.y;
-
- // Create a shape for saving the old position
- if(!gContRedraw)
- oldShape = GXCopyToShape(nil, hitShape);
-
- // Follow the drag around while the mouse is down
- while(StillDown())
- {
- // Get the new mouse position and if it's different,
- // adjust the dragged shape
- GXGetViewPortMouse(gViewPort, &pt);
- if(pt.x != lastPt.x || pt.y != lastPt.y)
- {
- // Save old shape so we can erase and draw in rapid succession
- if(!gContRedraw)
- GXCopyToShape(oldShape, hitShape);
-
- // Move it
- if(shapeNum == 0)
- DragLineShape(hitShape, &pt, &lastPt, &anchor, constrainH);
- else
- DragGlideShape(hitShape, &pt, &lastPt, &anchor, constrainH,
- arrowHit);
-
- if(gContRedraw)
- {
- // Reset pattern and draw it right now
- cm_ChangeLattice();
- OffToScreen();
- }
- else
- {
- // Erase and draw
- EraseAShape(oldShape);
- GXDrawShape(hitShape);
- }
- }
- lastPt = pt;
- }
- if(!gContRedraw)
- {
- cm_ChangeLattice(); // Update the pattern
- GXDisposeShape(oldShape);
- }
- return true;
- }
- else // no shape hit
- return false;
- }
-
- // Called either to set the default shapes when resetting the tile, or when
- // the symmetry has changed, to convert one lattice type to another.
- // Currently only resets to default
- void cm_RemakeOpShapes(Boolean useDefaults)
- {
- gxShape tempShape;
- gxLine aLine;
-
- if(true /* useDefaults */)
- {
- tempShape = MakeOpShape(reflOp);
- GXMoveShape(tempShape, kStartingOffset, kStartingOffset);
- gOpShapes[0] = tempShape;
- tempShape = MakeOpShape(glideOp);
- GXMoveShape(tempShape, kStartingOffset + (kStartingGridSize / 2),
- kStartingOffset);
- gOpShapes[1] = tempShape;
- }
- }
-
- // Set the dragger to the default shape.
- void cm_SetDefaultDragger(gxShape snake)
- {
- long dragPoly[] = { 1, // number of contours
- 3, // number of points
- ff(0), ff(64),
- ff(0), ff(0),
- ff(64), ff(0) };
-
-
- // make the starting drag shape
- GXSetPolygons(snake, (gxPolygons *) dragPoly);
- GXMoveShape(snake, kStartingOffset, kStartingOffset);
-
- // Reset the pattern to match the op shapes
- cm_ChangeLattice();
- }
-
- // Reset the pattern vectors according to the positions of the op shapes
- void cm_ChangeLattice(void)
- {
- gxLine line1, line2;
-
- // Adjust points to define the true unit cell.
- GXGetLine(gOpShapes[0], &line1);
- GXGetLine(gOpShapes[1], &line2);
- gPattern.u.x = 4 * (line2.first.x - line1.first.x);
- gPattern.u.y = 0;
- gPattern.v.x = 0;
- gPattern.v.y = 2 * (line2.last.y - line2.first.y);
-
- // Now remake the pattern according to the new lattice and draw it offscreen
- RemakeTile();
- }
-
- // Repeat the dragger geometry as necessary to build up the full unit cell
- void cm_BuildCellShape(gxShape snake)
- {
- gxShape tempShape;
- gxLine aLine;
- gxPoint ctr;
- fixed dist;
-
- // Get the point to glide reflect around
- GXGetLine(gOpShapes[1], &aLine);
- ctr.x = aLine.first.x;
- ctr.y = 0;
- //ctr.x += gPattern.u.x / 4;
-
- // Get the glide distance
- dist = gPattern.v.y / 2;
-
- // Copy the shape, glide reflect it, and add it back in
- tempShape = GXCopyToShape(nil, gTileShape);
- GXMoveShape(tempShape, 0, dist);
- GXScaleShape(tempShape, -ff(1), ff(1), ctr.x, ctr.y);
- GXSetShapeParts(gTileShape, 0, gxSelectToEnd, tempShape, gxBreakLeftEdit);
- GXDisposeShape(tempShape);
-
- // Then reflect the whole thing
- // Get the point to reflect around
- GXGetLine(gOpShapes[0], &aLine);
- ctr.x = aLine.first.x;
- //ctr.x += gPattern.u.x;
-
- // Copy the shape, reflect it, and add it back in
- tempShape = GXCopyToShape(nil, gTileShape);
- GXScaleShape(tempShape, -ff(1), ff(1), ctr.x, ctr.y);
- GXSetShapeParts(gTileShape, 0, gxSelectToEnd, tempShape, gxBreakLeftEdit);
- GXDisposeShape(tempShape);
- }
-
-
-